package framework.controller;

import org.json.simple.*;
import org.json.simple.parser.*;

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

import framework.utils.*;
import framework.utils.dto.Challenge;
import framework.event.CustomEvent;
import framework.gui.LobbyGUI;
import framework.model.*;
import framework.view.*;

/**
 * @class GameController
 * @author Michel Jansma
 * @version 0.1
 */
public class GameController extends ServerController {

	private JSONObject gameSettings;
	
	/**********************
	 *** GLOBAL METHODS ***
	 *********************/
	
	/**
	 * Initialize controller
	 * @method GameController (Constructor)
	 * @param <GameModel> model
	 */
	public GameController(GameModel model) {
		super(model);
		super.setCurrentListener(this);
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		CustomEvent event = (CustomEvent)e;
		switch(e.getActionCommand()) {
			case "YOURTURN" :
				this.handleTurnResponse();
			break;
			case "MOVE" :
				this.handleMoveResponse(event.getList());
			break;
			case "WIN" :
				this.getModel().setGameMessage("YOU WON THE GAME");
			break;
			case "LOSS" :
				this.getModel().setGameMessage("YOU LOST THE GAME");
			break;	
		};
	};
	
	/**********************
	 *** SETTER METHODS ***
	 *********************/
	
	/**
	 * Convert JSON - GameSettings file to JSON object
	 * @exception FileNotFoundException, ParseException
	 * @method setGameSettings
	 * @throws FileNotFoundException
	 */
	public void setGameSettings() throws Exception  {
		this.gameSettings = JSONReader.getGameSettings(this.getModel().getSettingsFile());
		if(this.gameSettings == null) {
			throw new FileNotFoundException();
		};
	};
	
	/**
	 * @method setBoard
	 */
	public void setBoard() {
		//Get board data
		JSONObject board = (JSONObject) this.gameSettings.get("board");
		this.getModel().setBoardSize(
			Integer.parseInt(board.get("width").toString()), 
			Integer.parseInt(board.get("height").toString())
		);
		//Update board
		this.getModel().update("board");
	};
	
	/**
	 * @method setResources
	 */
	public void setResources() {
		//Get resources
		JSONObject resources = (JSONObject)this.gameSettings.get("resources");
		this.getModel().getPlayer(1).put("resource", resources.get("playerOne").toString());
		this.getModel().getPlayer(2).put("resource", resources.get("playerTwo").toString());
	};
	
	/**********************
	 *** GETTER METHODS ***
	 *********************/
	
	@Override
	protected GameModel getModel() {
		return (GameModel) super.getModel();
	};
	
	/**
	 * @method getSettingsDialog
	 * @param <JFrame> frame
	 */
	public void getSettingsDialog(JFrame frame) {
		SettingsView dialog = new SettingsView(this, this.getModel(), frame);
		dialog.initialize();
	};
	
	/**********************
	 *** HANDLE METHODS ***
	 *********************/
	
	public void handleSettingsDialog(SettingsView dialog) {
		try {
			//GameSettings
			this.gameSettings = new JSONObject();
			//Board size
			HashMap<String,Integer> board = new HashMap<String,Integer>();
			board.put("width", dialog.getBoardWidth());
			board.put("height", dialog.getBoardWidth());
			this.gameSettings.put("board", board);
			//Resources
			HashMap<String,String> resources = new HashMap<String,String>();
			resources.put("playerOne", dialog.getPlayerOneResource());
			resources.put("playerTwo", dialog.getPlayerTwoResource());
			this.gameSettings.put("resources", resources);
			//Update GameSettings
			JSONReader.setGameSettings(this.getModel().getSettingsFile(), this.gameSettings);
			//Close dialog
			dialog.dispose();
		} catch(Exception e) {
			System.out.println("F***Y**");
		};
	};
	
	/**
	 * Handle move request by grid id
	 * @method handleMoveRequest
	 * @param <Integer> move
	 */
	public void handleMoveRequest(int move) {
		//Move board Column
		int x = move%this.getModel().getBoardWidth();
		//Move board Row
		int y = move/this.getModel().getBoardHeight();
		//Check if move is valid
		if(this.getModel().isValidMove(move)) {
			//Send move command to GameServer
			super.sendCommand("move " + x + "," + y);
		} else {
			System.err.println("INVALID MOVE REQUEST");
		};
	};
	
	/**
	 * Move response from GameServer
	 * @method handleMoveResponse
	 */
	public void handleMoveResponse(ArrayList<String> list) {
		if(list.size() == 3) {
			//Get index of player
			int player = this.getModel().getPlayerIndex(list.get(0).toString());
			//X,Y values of board
			String[] _2D = list.get(2).split(",");
			//Cast to field id
			int move = this.getModel().board2DToId(
				Integer.parseInt(_2D[0]),
				Integer.parseInt(_2D[1])
			);
			//Do move
			this.getModel().doPlayerMove(player,move);
		};
	};
	
	public void handleTurnResponse() {
		//It's your turn
		this.getModel().setCurrentPlayer(this.getModel().getPlayerIndex());
		if(this.getModel().getAIRunning()) {
			this.handleMoveRequest(this.getModel().bestMove());	
		};
	};

	public void handleShutdownRequest() {
		new LobbyGUI();
	};
	
	public void handleForfeitRequest() {
		super.sendCommand("forfeit");
	};
	
	public void toggleAutoplay() {
		boolean autoplay = this.getModel().getAIRunning();
		this.getModel().setAIRunning(autoplay ? false : true);
	};
	
	public void handleStepRequest() {
		this.handleMoveRequest(this.getModel().bestMove());
	};
	
}
